# -*- coding: utf-8 -*-
import json
import logging
import time
import uuid

import requests

from flask import request, url_for, make_response

from . import api, utils, gen_url, urls
from .utils import admin_only

LOGGER = logging.getLogger(__name__)


# Project
@api.route('/projects')
def list_projects():
    username = request.headers['user_name']

    _, co_projects = utils.get_co_projects(username)
    s, self_projects = utils.get_self_projects(username)
    print 'get self projects: %s, %s' % (s, self_projects)

    resp = {
        'status': 0,
        'msg': 'success',
        'data': {
            'self_pro': self_projects,
            'cor_pro': co_projects,
        }}
    return resp


@api.route('/projects', methods=['POST'])
@admin_only
def new_project():
    user_name = request.headers['user_name']

    args = request.form
    s, m = utils.new_project(user_name, args['project_name'])
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


@api.route('/projects/<project_id>/starred', methods=['PUT'])
@admin_only
def mark_as_default_project(project_id):
    user_name = request.headers['user_name']
    s, m = utils.set_default_project(user_name, project_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


@api.route('/projects/<project_id>')
def get_project_info(project_id):
    user_id = request.headers['user_name']

    s, m = utils.get_project_profile(project_id)
    if s:
        return {'status': s, 'msg': 'fail', 'data': m}

    project_profile = m

    if user_id == project_profile['owner_id']:
        # user is the owner of the project.
        project_members = utils.get_project_members(user_id, project_id)
    else:
        project_members = utils.get_coproject_members(user_id, project_id)

    _, project_clusters = utils.get_project_clusters(project_id)

    resp = {
        'status': 0,
        'msg': 'success',
        'data': {
            'project_id': project_id,
            'project_name': project_profile.get('project_name'),
            'owner': project_profile.get('owner'),
            'owner_id': project_profile.get('owner_id'),
            'members': project_members,
            'clusters': project_clusters,
        }
    }
    return resp


@api.route('/projects/<project_id>', methods=['DELETE'])
def delete_project(project_id):
    user_id = request.headers['user_name']

    if not utils.is_project_exists(project_id):
        return dict(status=404, msg='fail', data=u'无此项目')

    if not utils.is_project_admin(user_id, project_id, True):
        return dict(status=403, msg='fail', data=u'您不是该项目创建者!')

    s, m = utils.delete_project(project_id, user_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


# Project.Usage
@api.route('/projects/<project_id>/statistics')
def get_project_resource_statistics(project_id):
    user_name = request.headers['user_name']

    if not utils.is_project_exists(project_id):
        return dict(status=404, msg='fail', data=u'无此项目')

    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结')
        if not utils.check_permission(user_name, project_id, 'dashboard', 'r'):
            return dict(status=403, msg='fail', data=u'您无权查看统计数据')

    s, m = utils.get_project_statistics(user_name, project_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


# Project.Clusters
@api.route('/projects/<project_id>/clusters')
def list_project_attached_clusters(project_id):
    try:
        is_revert = int(request.args.get('revert', 0))

        s, m = utils.get_project_clusters(project_id, is_revert)
        resp = {
            'status': s,
            'msg': 'fail' if s else 'success',
            'data': m,
        }
    except ValueError:
        resp = {
            'status': 1,
            'msg': 'fail',
            'data': 'revert should be an integer not char!',
        }
    return resp


@api.route('/projects/<project_id>/clusters', methods=['POST'])
def attach_cluster_to_project(project_id):
    user_name = request.headers['user_name']

    if not utils.is_project_admin(user_name, project_id):
        return dict(status=403, msg='fail', data=u'您不是该项目管理者!')

    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')

    args = request.form
    cluster_id = args['cluster_id']

    s, m = utils.attach_cluster_to_project(project_id, cluster_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


@api.route('/projects/<project_id>/clusters/<cluster_id>', methods=['DELETE'])
def dettach_cluster_to_project(project_id, cluster_id):
    user_name = request.headers['user_name']

    if not utils.is_project_admin(user_name, project_id):
        return dict(status=403, msg='fail', data=u'您不是该项目管理员!')

    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')

    s, m = utils.dettach_cluster_from_project(project_id, cluster_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


# Project.Flavors
@api.route('/flavors')
def list_flavors():
    s, m = utils.list_flavors()
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


@api.route('/images', methods=['GET'])
def list_project_images():
    args = request.args
    cluster_id = args['cluster_id']

    images = {}

    # TODO: support `os_type` in the future!

    s, linux_images = utils.list_images_by_os(cluster_id, 'linux')
    if not s and linux_images:
        images['linux'] = linux_images

    s, windows_images = utils.list_images_by_os(cluster_id, 'windows')
    if not s and windows_images:
        images['windows'] = windows_images

    resp_status = 1 if not images else 0
    resp = {
        'status': resp_status,
        'msg': 'fail' if resp_status else 'success',
        'data': images,
    }
    return resp


@api.route('/images/<image_id>', methods=['GET'])
def get_image(image_id):
    s, m = utils.get_image_info(image_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


# Instance.health
@api.route('/instances/<instance_id>/health')
def get_instance_health_data(instance_id):
    args = request.args

    metric = args['metric']
    stime = float(args['stime'])
    etime = float(args['etime'])

    time_fmt = '%Y/%m/%d-%H:%M:%S'
    stime = time.strftime(time_fmt, time.localtime(stime))
    etime = time.strftime(time_fmt, time.localtime(etime))

    s, m = utils.get_instance_health_data(instance_id, metric,
                                          stime, etime)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


# Instance.OPlog
@api.route('/instances/<instance_id>/oplog')
def get_instance_oplog(instance_id):
    args = request.args

    try:
        page_size = int(args.get('page_size', 10))
        page_num = int(args.get('page_num', 0))

        offset = page_size * page_num

        s, m = utils.get_instance_oplog(instance_id, page_size, offset)
        resp = {
            'status': s,
            'msg': 'fail' if s else 'success',
            'data': m,
        }
        return resp
    except ValueError, ve:
        LOGGER.exception(ve.message)
        return dict(status=4, msg='fail', data=str(ve))


# Instance.VNC
@api.route('/instances/<instance_id>/vnc')
def get_instance_vnc(instance_id):
    status, data = utils.get_instance_info(instance_id)
    if status:
        LOGGER.error('Find instance %s: %s!', instance_id, data)
        return dict(status=status, msg='fail', data=data)

    cluster_id = data['cluster_id']
    project_id = data['project_id']
    user_name = request.headers['user_name']
    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')
        if not utils.check_permission(user_name, project_id, 'vps', 'u'):
            return dict(status=403, msg='fail', data=u'您无权进入虚拟机!')

    s, m = utils.get_vnc(cluster_id, instance_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return dict(resp)


# Instances Interface
@api.route('/instances/<instance_id>/interfaces', methods=['POST'])
def attache_interface(instance_id):
    args = request.form

    # project_id = args['project_id']
    net_id = args['net_id']
    fixed_ip = args.get('fixed_ip')

    s, m = utils.attach_interface(instance_id, net_id, fixed_ip)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return dict(resp)


@api.route('/instances/<instance_id>/interfaces/<port_id>', methods=['DELETE'])
def detach_interface(instance_id, port_id):
    # project_id = args['project_id']

    s, m = utils.dettach_interface(instance_id, port_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return dict(resp)


@api.route('/instances/<instance_id>/interfaces')
def show_instance_interface(instance_id):
    # args = request.form

    # project_id = args['project_id']

    s, m = utils.list_instance_interface(instance_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return dict(resp)


# Instance.List
@api.route('/instances')
def list_project_instances():
    args = request.args
    project_id = args['project_id']
    excludes = args.get('excludes', 'deleted')

    user_name = request.headers['user_name']
    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')

        if not utils.check_permission(user_name, project_id, 'vps', 'r'):
            return dict(status=403, msg='fail', data=u'您无权查看该项目的虚拟机列表!')

    s, m = utils.list_project_instances(project_id, excludes)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return dict(resp)


# Instance.Create
@api.route('/instances', methods=['POST'])
def spawn_instance():
    args = request.form

    project_id = args['project_id']
    idc_name = args['idc_name']
    cluster_id = args['cluster_id']
    image_id = args['img_id']
    image_uuid = args['img_uuid']
    # image_name = args['img_name']
    flavor_id = args['flavor_id']
    flavor_uuid = args['flavor_uuid']

    # flavor_name = args['flavor_name']
    need_pub = int(args.get('need_pub', 0))
    os = args.get('os', 'linux')
    hostname = args.get('hostname', None)
    # user_name = args['user_name']
    router_path = '/etc/sysconfig/network-scripts/route-eth0'

    user_name = request.headers['user_name']
    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')

        # Check action permission
        if not utils.check_permission(user_name, project_id, 'vps', 'c'):
            return dict(status=403, msg='fail', data=u'您无权创建虚拟机!')

    LOGGER.info('arguments: %s', args)
    print 'Starting create vm: %s' % args

    vm_name = '_'.join([idc_name, os, cluster_id, uuid.uuid4().hex[:7]])
    create_time = time.strftime('%Y-%m-%d %H:%M:%S')

    if os == 'linux':
        key_name = args['key_name']
        values = {
            'cluster_id': cluster_id,
            'image_id': image_uuid,
            'flavor_id': flavor_uuid,
            'vm_name': vm_name,
            'hostname': hostname or vm_name,
            'user': user_name,
            'key_name': key_name,
            'router_path': router_path,
            'create_time': create_time,
        }
    else:
        values = {
            'image_id': image_uuid,
            'flavor_id': flavor_uuid,
            'cluster_id': cluster_id,
            'user': user_name,
            'vm_name': vm_name,
            # 'key_name': '',
            # 'key_content': key_content,
            'create_time': create_time,
            # 'router_path': 'Users\\123.txt',
        }

    if hostname:
        values['hostname'] = hostname

    if need_pub:
        new_ip = utils.request_new_ip(cluster_id)
        LOGGER.info('Request ip from cluster(%s): %s', cluster_id, new_ip)
        if new_ip is None:
            return dict(status=1, msg='failed', data='allocation IP failed')

        ip_info = new_ip
        values.update(public_ip=ip_info['ip'],
                      netmask=ip_info['netmask'],
                      gateway=ip_info['gateway'])
        LOGGER.info(values)
    else:
        ip_info = None

    LOGGER.info("create vm arguments: %r", values)

    # url = gen_url('instance_create')
    # r = requests.post(url, data=values)
    # LOGGER.info("create vm result(%s, %s): %s",
    #             r.status_code, r.reason, r.content)

    s, m = utils.create_instance(values)
    if s:
        LOGGER.error('create vm failed: %s', m)
        return dict(status=1, msg='failed', data=m)

    ret = m
    LOGGER.info('Create vm: %s', ret)

    if ret['status'].lower() == 'success':
        instance_id = ret['result']['instance_id']
        create_time = time.strftime('%Y-%m-%d %H:%M:%S')

        if os == 'linux':
            vm_record = {
                'instance_id': instance_id,
                'idc': idc_name,
                'cluster': cluster_id,
                'cluster_id': cluster_id,
                'vm_name': vm_name,
                'image_id': image_id,
                'flavor_id': flavor_id,
                'user_id': user_name,
                'public_ip': ip_info['ip'] if ip_info else '',
                'key_name': key_name,
                'create_time': create_time,
                'project_id': project_id
            }
        else:
            vm_record = {
                'instance_id': instance_id,
                'idc': idc_name,
                'cluster': cluster_id,
                'cluster_id': cluster_id,
                'vm_name': vm_name,
                'image_id': image_id,
                'flavor_id': flavor_id,
                'user_id': user_name,
                'public_ip': ip_info['ip'] if ip_info else '',
                'create_time': create_time,
                'project_id': project_id,
            }

        utils.instance_status_create(vm_record)

        ret['result'].update(create_time=create_time)
        LOGGER.debug(ret)

        # Fix `X-Forwarded-Proto`
        _scheme = request.headers.get('X-Forwarded-Proto', 'http')
        header = {'Location': url_for('api.show_instance',
                                      instance_id=instance_id,
                                      _external=True,
                                      _scheme=_scheme)}
        return dict(status=0, msg='success', data=ret), 201, header
    else:
        LOGGER.error('Create vm failed(%s): %s', ret['task_id'], ret['result'])

        # release IP
        if ip_info is not None:
            LOGGER.debug('Releasing ip: %s', ip_info)
            utils.release_ip(ip_info['ip'])

        return dict(status=2, msg='fail', data=m)


# Instance
@api.route('/instances/<instance_id>', methods=['GET'])
def show_instance(instance_id):
    s, m = utils.get_instance_info(instance_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


# Instance.Delete
@api.route('/instances/<instance_id>', methods=['DELETE'])
def destroy_instance(instance_id):
    status, data = utils.get_instance_info(instance_id)
    if status:
        LOGGER.error('Find instance %s: %s!', instance_id, data)
        return dict(status=status, msg='fail', data=data)

    cluster_id = data['cluster_id']
    project_id = data['project_id']

    user_name = request.headers['user_name']
    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')
        if not utils.check_permission(user_name, project_id, 'vps', 'd'):
            return dict(status=403, msg='fail', data=u'您无权删除虚拟机!')

    s, m = utils.destroy_instance(instance_id, cluster_id)
    a, b = utils.instance_status_update('destroy', instance_id, cluster_id)
    print a, b
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


# Instance.Tag
@api.route('/instances/<instance_id>', methods=['PATCH'])
def patch_instance(instance_id):
    s, instance_info = utils.get_instance_info(instance_id)
    if s or not instance_info:
        return dict(status=404, msg='fail', data=u'无法查询到此虚拟机!')

    project_id = instance_info['project_id']
    x_user = request.headers['user_name']
    if not utils.is_project_admin(x_user, project_id, True):
        if not utils.is_active(project_id, x_user):
            return dict(status=403, msg='fail', data=u'您已被冻结!')
        if not utils.check_permission(x_user, project_id, 'vps', 'u'):
            return dict(status=403, msg='fail', data=u'您无权修改虚拟机备注!')

    args = request.form
    tag = args['tag']

    s, ret = utils.patch_instance(instance_id,
                                  x_user,
                                  tag)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': ret,
    }
    return resp


# Instance.Action
@api.route('/instances/<instance_id>/action',
           methods=['POST'])
def touch_instance(instance_id):
    args = request.form
    action = args.get('action')

    s, m = utils.get_instance_info(instance_id)
    if s:
        return dict(status=1, msg='fail', data='Find instance: %s' % m)

    cluster_id = m['cluster_id']
    project_id = m['project_id']

    # Check user permission in this project.
    user_name = request.headers['user_name']
    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')
        if not utils.check_permission(user_name, project_id, 'vps', 'u'):
            return dict(status=403, msg='fail', data=u'您无权更改虚拟机运行状态!')

    if action == 'start':
        s, m = utils.start_instance(instance_id, cluster_id)

    elif action == 'stop':
        s, m = utils.stop_instance(instance_id, cluster_id)

    elif action == 'reboot':
        is_hard = int(args.get('hard', 0))
        print 'is_hard: %s, %s' % (is_hard, type(is_hard))
        s, m = utils.restart_instance(instance_id, cluster_id, is_hard)
    else:
        s, m = 1, 'Invalid action!'

    if not s:
        update_s, update_m = utils.instance_status_update(action,
                                                          instance_id,
                                                          cluster_id)
        print 'update: %s, %s' % (update_s, update_m)
        print '%s instance %s: %s, %s!' % (action, instance_id, s, m)

    return {'status': s, 'msg': m, 'data': ''}


# Search
@api.route('/search')
def search_instance():
    args = request.args
    search_k = args['k']
    search_v = args['v']
    project_id = args['project_id']

    s, m = utils.search_instance_in_project(project_id, search_k, search_v)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


# Project.Key
@api.route('/projects/<string:project_id>/keys')
def list_project_keypairs(project_id):
    user_name = request.headers['user_name']

    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')

        if not utils.check_permission(user_name, project_id, 'vps', 'r'):
            return dict(status=403, msg='fail', data=u'您无权查看密钥对列表!')

    s, m = utils.list_project_keypairs(project_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


@api.route('/projects/<project_id>/keys_gen', methods=['POST'])
def gen_project_keypairs(project_id):
    user_name = request.headers['user_name']
    if not utils.is_project_admin(user_name, project_id, only_creator=True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')
        if not utils.check_permission(user_name, project_id, 'vps', 'c'):
            return dict(status=403, msg='fail', data=u'您无权创建密钥对!')

    args = request.form
    show_name = args.get('show_name')
    # key_id = '%s_%s' % (project_id.split('-')[1], uuid.uuid4().hex[:4]),
    key_id = '_'.join(['sk', uuid.uuid4().hex[:4], user_name])

    cluster_ids = utils.get_project_clusters_ids(project_id)

    if cluster_ids:
        # auto create
        first_cid = cluster_ids.pop(0)

        print 'project_id = %s' % project_id
        print 'user_id = %s' % user_name
        print 'key_id = %s' % key_id

        ok, new_key = utils.create_single_keypair(project_id, first_cid,
                                                  user_name, key_id, show_name)

        if not ok:
            return {'status': 2, 'msg': 'fail', 'data': new_key}

        # post keypairs
        for cid in cluster_ids:
            values = {
                'project_id': project_id,
                'cluster_id': cid,
                'user_id': user_name,
                'key_id': key_id,
                'key_content': new_key['public_key'],
                'show_name': show_name,
            }
            utils.post_single_keypairs(**values)

        # resp = make_response(new_key['private_key'])
        # headers = {
        #     'Content-Type': 'application/octet-stream',
        #     'Content-Disposition': 'attachment; filename=%s.pem' % key_id,
        # }
        # resp.headers.extend(headers)
        resp = {
            'status': 0,
            'msg': 'success',
            'data': {
                'private_key': new_key['private_key'],
                'key_name': show_name,
            },
        }
        return resp, 201
    else:
        return {'status': 1, 'msg': 'fail', 'data': 'cluster not found'}


@api.route('/projects/<project_id>/keys', methods=['POST'])
def post_project_keypairs(project_id):
    user_name = request.headers['user_name']

    args = request.form
    show_name = args['show_name']
    public_key = args['public_key']

    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')
        if not utils.check_permission(user_name, project_id, 'vps', 'c'):
            return dict(status=403, msg='fail', data=u'您无权创建密钥对!')

    cluster_ids = utils.get_project_clusters_ids(project_id)
    print 'cluster_ids: %s' % cluster_ids

    if cluster_ids is None:
        resp = {
            'status': 1,
            'msg': 'fail',
            'data': 'No cluster attached on this project!',
        }
    else:
        key_id = '%s_%s' % (project_id, uuid.uuid4().hex[:4])
        for c_id in cluster_ids:
            print 'cluster: %s' % c_id
            s, m = utils.post_single_key(c_id, project_id, user_name,
                                         key_id, show_name, public_key)

        print '%s:%s' % (s, m)
        if s:
            resp = {
                'status': s,
                'msg': 'fail',
                'data': m,
            }
        else:
            resp = {
                'status': 0,
                'msg': 'success',
                'data': {
                    'key_id': key_id,
                    'show_name': show_name,
                    'fingerprint': m['fingerprint'],
                },
            }
    return resp


@api.route('/projects/<project_id>/keys/<key_id>', methods=['DELETE'])
def delete_project_keypairs(project_id, key_id):
    user_name = request.headers['user_name']

    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')
        if not utils.check_permission(user_name, project_id, 'vps', 'd'):
            return dict(status=403, msg='fail', data=u'您无权删除秘钥对!')

    key_ids = key_id.split(',')

    if len(key_ids) > 5:
        return dict(status=1, msg='fail', data=u'太多了,忙不过来!')

    results = []
    for kid in key_ids:
        s, m = utils.delete_single_keypairs(project_id, kid)
        if s:
            results.append([s, m])

    if results:
        results = dict(results)
        resp = {
            'status': len(results),
            'msg': 'fail',
            'data': u'删除失败: %s!' % ';'.join(results.values()),
        }
    else:
        resp = {
            'status': 0,
            'msg': 'success',
            'data': 'All keypairs are remove from %s' % project_id,
        }

    return resp


# User
@api.route('/users/<user_name>')
def get_user_profile(user_name):
    """ Get user profile from database.

    If user not found in database, return error.

    :param user_name: user's name.
    """
    if user_name == 'me':
        user_name = request.headers['user_name']

    # Get User from DB.
    s, resp_data = utils.get_user_profile(user_name)
    if s:
        LOGGER.error('Find user %s: %s', user_name, resp_data)
        return {
            'status': 1,
            'msg': 'fail',
            'data': u'查询用户失败',
        }
    elif not resp_data:
        return {
            'status': 2,
            'msg': 'fail',
            'data': u'用户不存在',
        }
    else:
        return {
            'status': s,
            'msg': 'success',
            'data': resp_data,
        }


@api.route('/users/<user_name>', methods=['PUT'])
def modify_user_profile(user_name):
    if user_name != request.headers['user_name']:
        return dict(status=403, msg='fail', data=u'您无权修改他人信息!')

    args = request.form
    phone_number = args.get('phone_number')
    if phone_number is None:
        resp = {
            'status': 1,
            'msg': 'missing phone_number field',
            'data': ''
        }
    else:
        resp = {
            'status': 0,
            'msg': 'Your phone number %s is activated now!' % phone_number,
            'data': ''
        }
    return resp


# User.Member
@api.route('/users/<user_name>/members')
@admin_only
def list_user_members(user_name):
    # FIXME: 重置user_name为当前认证用户, 忽略用户参数
    x_user = request.headers['user_name']

    if user_name == 'me':
        user_name = x_user

    args = request.args
    project_id = args.get('project_id', None)
    revert = int(args.get('revert', 0))

    if project_id:
        # Get members not in `project_id`
        if revert:
            s, m = utils.get_member_not_in_project(user_name, project_id)
        # Get members already in `project_id`
        else:
            s, m = utils.get_member_in_project(user_name, project_id)
    else:
        # Get all members
        s, m = utils.get_all_members(user_name)

    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


@api.route('/users/<user_name>/members', methods=['POST'])
@admin_only
def invite_member_by_email(user_name):
    x_user = request.headers['user_name']

    if user_name == 'me':
        user_name = x_user

    args = request.form
    member_email = args.get('email')
    if user_name != x_user:
        return dict(status=403, msg='fail', data=u'您无权修改他人信息!')

    s, m = utils.invite_member_by_email(user_name, member_email)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


@api.route('/users/<user_name>/members/<member_id>', methods=['PUT'])
@admin_only
def modify_member_status(user_name, member_id):
    x_user = request.headers['user_name']

    if user_name == 'me':
        user_name = x_user

    args = request.form
    action = args.get('action', None)
    if user_name != x_user:
        return dict(status=403, msg='fail', data=u'您无权修改他人信息!')

    if action is None:
        resp = {
            'status': 1,
            'msg': 'fail',
            'data': 'Invalid action: %s' % action,
        }
        return resp

    if action == 'freeze':
        s, m = utils.freeze_member(user_name, member_id)
    elif action == 'unfreeze':
        s, m = utils.unfreeze_member(user_name, member_id)
    elif action == 'cancel':
        s, m = utils.cancel_member(user_name, member_id)
    else:
        s, m = 1, 'Invalid action.'

    resp_data = 'failed' if s else 'success'
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': '%s %s %s: %s!' % (action, member_id, resp_data, m),
    }
    return resp


# User.Project.Member
@api.route('/users/<user_name>/projects/<project_id>/members')
def list_project_members(user_name, project_id):
    x_user = request.headers['user_name']
    if user_name == 'me':
        user_name = x_user

    if user_name != x_user:
        return dict(status=403, msg='fail', data=u'您无权查看他人信息!')
    try:
        revert = int(request.args.get('revert', 0))

        # Get members not in `project_id`
        if revert:
            s, m = utils.list_member_not_in_project(project_id)
            # Get members already in `project_id`
        else:
            s, m = utils.list_member_in_project(user_name, project_id)
    except ValueError:
        s, m = 1, 'revert should be an integer not str!'

    return {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }


@api.route('/users/<user_name>/projects/<project_id>/members',
           methods=['POST'])
def attach_member_to_project(user_name, project_id):
    x_user = request.headers['user_name']

    if user_name == 'me':
        user_name = x_user

    # 如果是非ADMIN角色 => 403
    if not utils.is_project_admin(user_name, project_id):
        return dict(status=403, msg='fail', data=u'您不是管理员!')

    # 如果是创建者 => pass
    # 如果是其他ADMIN => is_active?
    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')

    args = request.form
    member_id = args['member_id']
    role_id = args['role_id']

    s, m = utils.attach_member_to_project(user_name, project_id,
                                          member_id, role_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


@api.route('/users/<user_name>/projects/<project_id>/members/<member_id>',
           methods=['DELETE'])
def dettach_member_from_project(user_name, project_id, member_id):
    # Check user in the project.
    user_name = request.headers['user_name']
    if not utils.is_project_admin(user_name, project_id):
        return dict(status=403, msg='fail', data=u'您不是该项目管理者!')

    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')

    s, m = utils.dettach_member_from_project(user_name, project_id, member_id)
    if s:
        resp = {
            'status': 1,
            'msg': 'fail' if s else 'success',
            'data': m,
        }
    else:
        resp = {
            'status': 0,
            'msg': 'success',
            'data': u'移除协作者成功!',
        }
    return resp


@api.route('/projects/<project_id>/members/<member_id>',
           methods=['PATCH'])
def patch_project_member(project_id, member_id):
    user_name = request.headers['user_name']

    if not utils.is_project_admin(user_name, project_id):
        return dict(status=403, msg='fail', data=u'您不是该项目管理者')

    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.is_active(project_id, user_name):
            return dict(status=403, msg='fail', data=u'您已被冻结!')

    role_id = request.form['role_id']

    s, m = utils.switch_role_for_project_member(user_name,
                                                member_id,
                                                project_id,
                                                role_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


# Role
@api.route('/roles')
@admin_only
def list_user_roles():
    x_user = request.headers['user_name']
    creator = request.args.get('user_name', x_user)

    s, m = utils.list_roles_by_creator(creator)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


@api.route('/roles', methods=['POST'])
@admin_only
def add_role():
    x_user = request.headers['user_name']

    args = request.form
    role_name = args['role_name']

    permissions = {
        'dashboard': args.get('dashboard', ''),
        'vps': args.get('vps', ''),
        'cdn': args.get('cdn', ''),
    }

    # Create new role.
    s, m = utils.add_single_role(x_user, role_name)
    if s:
        resp = {
            'status': s,
            'msg': m,
            'data': '',
        }
        return resp

    # Set Permissions
    role_id = m
    s, m = utils.new_role_permissions(role_id, **permissions)
    if s:
        resp = {
            'status': s,
            'msg': 'fail',
            'data': m,
        }
        return resp

    resp = {
        'status': 0,
        'msg': 'success',
        'data': {
            'role_id': role_id,
            'role_name': role_name,
            'creator': x_user,
        }
    }
    return resp


@api.route('/roles/<role_id>')
@admin_only
def get_role(role_id):
    # Get role profile
    s, ret = utils.get_role_profile(role_id)
    print 'get profile: %s, %s' % (s, ret)
    if s:
        return {'status': s, 'msg': ret, 'data': ''}

    role_name = ret['role_name']

    # Get role's permission
    s, ret = utils.get_role_permissions(role_id)
    print 'permission: %s, %s' % (s, ret)
    if s:
        return {'statul': s, 'msg': 'fail', 'data': ret}

    return {
        'status': 0,
        'msg': 'success',
        'data': {
            'role_id': role_id,
            'role_name': role_name,
            'permissions': ret,
        }
    }


@api.route('/roles/<role_id>', methods=['PUT'])
def update_role_permission(role_id):
    x_user = request.headers['user_name']
    if not utils.is_role_creator(role_id, x_user):
        return dict(status=403, msg='fail', data=u'您不是该角色的创建者!')

    args = request.form
    permissions = {
        'dashboard': args['dashboard'],
        'vps': args['vps'],
        'cdn': args['cdn'],
    }
    s, m = utils.update_role_permissions(role_id, **permissions)

    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


@api.route('/roles/<role_id>', methods=['DELETE'])
def delete_role(role_id):
    # Check role creator.
    x_user = request.headers['user_name']
    if not utils.is_role_creator(role_id, x_user):
        return dict(status=403, msg='fail', data=u'您不是该角色创建者!')

    s, m = utils.delete_role(role_id)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


# CDN
@api.route('/cdn/log')
def list_tasks_log():
    args = request.args
    project_id = args['project_id']

    user_name = request.headers['user_name']
    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.check_permission(user_name, project_id, 'cdn', 'r'):
            return dict(status=403, msg='fail', data=u'您无权查看CDN日志!')

    stime = args.get('stime')
    etime = args.get('etime')

    time_fmt = '%Y-%m-%d %H:%M:%S'
    if stime is None:
        stime = '2015-12-01 00:00:00'
    else:
        stime = time.strftime(time_fmt, time.localtime(float(stime)))

    if etime is None:
        etime = '2016-12-31 23:59:59'
    else:
        etime = time.strftime(time_fmt, time.localtime(float(etime)))

    limit_start = args.get('limit_start', 1)
    limit_end = args.get('limit_end', 25)

    print 'stime: %s' % stime
    print 'etime: %s' % etime

    s, m = utils.list_cdn_log(stime, etime, limit_start, limit_end)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


@api.route('/cdn/tasks')
def list_cdn_tasks():
    url = gen_url('cdn_tasks', host=urls['cdn_api'])
    r = requests.get(url, params=request.args, headers=request.headers)
    resp = make_response(r.content)
    resp.headers['X-Total-Count'] = r.headers['X-Total-Count']
    return resp


@api.route('/cdn/tasks/<tid>/steps')
def list_cdn_steps(tid):
    url = gen_url('cdn_steps', host=urls['cdn_api']).format(tid=tid)
    r = requests.get(url, params=request.args, headers=request.headers)
    return r.json()


@api.route('/cdn/purge', methods=['POST'])
def purge_files():
    url = gen_url('cdn_purge', host=urls['cdn_api'])
    files = json.loads(request.data)
    failed = []
    for f in files:
        try:
            r = requests.post(url,
                              data={'download_url': f,
                                    'user_name': request.headers['user_name']})
            if not r.ok:
                print f, r.status_code, r.reason
                failed.append(f)
        except Exception, e:
            failed.append(f)
            LOGGER.exception(e.message)

    if failed:
        return {'status': 1, 'msg': 'fail', 'data': failed}
    else:
        return {'status': 0, 'msg': 'ok', 'data': 'success'}


@api.route('/cdn/statistics')
def get_cdn_statistics():
    args = request.args

    project_id = args['project_id']
    user_name = request.headers['user_name']
    if not utils.check_permission(user_name, project_id, 'cdn', 'r'):
        return dict(status=403, msg='fail', data=u'您无权查看CDN日志!')

    q = args.get('q', 'projects')
    project_name = args.get('project_name', 'all')
    period_type = args.get('period_type', 'all')
    start_time = args.get('start_time', time.time())

    print 'project_name: %s' % project_name
    print 'period_type: %s' % period_type
    print 'start_time: %s' % start_time
    print 'q: %s, %s, %s' % (q, q == 'status', q in ('ftype', 'status'))

    try:
        if q == 'null':
            q = 'projects'

        if project_name == 'null':
            project_name = 'all'

        if period_type == 'null':
            period_type = 'all'

        if start_time == 'null':
            start_time = time.strftime('%Y-%m-%d')
        else:
            start_time = time.strftime('%Y-%m-%d', time.localtime(float(start_time)))

        if q == 'projects':
            s, m = utils.get_cdn_submit_stats(project_name, period_type, start_time, q)

        elif q == 'ftype':
            if project_name == 'all':
                s, m = 1, 'Invalid project_name'
            else:
                s, m = utils.get_cdn_submit_stats(project_name, period_type, start_time, q)

        elif q == 'status':
            if project_name == 'all':
                s, m = 1, 'Invalid project_name'
            else:
                s, m = utils.get_cdn_submit_stats(project_name, period_type, start_time, q)

        else:
            s, m = 1, 'Invalid param `q`: %s, %s!' % (q, type(q))

        resp = {
            'status': s,
            'msg': 'fail' if s else 'success',
            'data': m,
        }
    except Exception, e:
        resp = {
            'status': 1,
            'msg': 'fail',
            'data': str(e),
        }
    return resp


@api.route('/cdn/log/search')
def search_cdn_log():
    args = request.args

    project_id = args['project_id']
    user_name = request.headers['user_name']
    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.check_permission(user_name, project_id, 'cdn', 'r'):
            return dict(status=403, msg='fail', data=u'您无权查看CDN日志!')

    # TODO: q is for search term.
    # `log` is supported ONLY.
    # q = args.get('q', 'log')

    project_name = args.get('project_name')
    file_name = args.get('file_name')
    status = args.get('status')
    download_url = args.get('download_url')
    start_time = args.get('start_time')
    page = args.get('page', 0)
    page_size = int(args.get('page_size', 10))

    if status:
        status = int(status)

    # if page:
    #     page = int(page)

    if start_time:
        start_time = time.strftime('%Y-%m-%d', time.localtime(float(start_time)))

    s, m = utils.search_cdn_log(project_name, file_name, status,
                                download_url, start_time, page, page_size)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp


@api.route('/cdn/log/<task_id>')
def get_cdn_log_detail(task_id):
    args = request.args

    project_id = args['project_id']
    user_name = request.headers['user_name']
    if not utils.is_project_admin(user_name, project_id, True):
        if not utils.check_permission(user_name, project_id, 'cdn', 'r'):
            return dict(status=403, msg='fail', data=u'您无权查看CDN日志!')

    status = int(args.get('status', 1))
    s, m = utils.get_cdn_log_detail(task_id, status)
    resp = {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }
    return resp
